package com.xusiyan08.config;

import com.xusiyan08.entity.User.UserRole;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.SignatureException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;

import java.util.Arrays;
import java.util.List;

@Component
@Order(Ordered.HIGHEST_PRECEDENCE) // 确保过滤器尽早执行
public class JwtAuthenticationFilter implements WebFilter {

    private static final Logger logger = LoggerFactory.getLogger(JwtAuthenticationFilter.class);

    @Autowired
    private JwtUtil jwtUtil;

    // 定义所有不需要认证的精确匹配公共路径
    private static final List<String> EXACT_EXCLUDED_PATHS = Arrays.asList(
            "/",
            "/index.html",
            "/login",
            "/login.html",
            "/register.html",
            "/admin.html", // HTML文件本身是公开的
            "/favicon.ico",
            "/error",
            "/api/users/login",
            "/api/users/register",
            "/api/items", // 公开获取所有商品，不带认证
            "/get-port", // 允许无需认证访问负载均衡端口接口
            "/port" // 允许前端获取当前服务端口
    );

    // 定义所有不需要认证的前缀匹配公共路径 (例如静态资源目录)
    private static final List<String> PREFIX_EXCLUDED_PATHS = Arrays.asList(
            "/css/",
            "/js/",
            "/images/",
            "/webapp/", // 所有 /webapp/ 下的静态资源
            "/actuator/health", // 健康检查 API
            "/swagger-ui/", // Swagger UI
            "/v3/api-docs/", // Swagger API docs
            "/webjars/", // Webjars (Swagger 依赖)
            "/api/feign-test/",
            "/api/items/" // 允许 Feign 客户端内部调用商品接口
    );

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String path = request.getPath().value();
        logger.debug("Processing request for path: {}", path);

        // 检查是否是精确匹配的公共路径
        if (EXACT_EXCLUDED_PATHS.contains(path)) {
            logger.debug("Path {} is an exact public path. Bypassing JWT authentication.", path);
            return chain.filter(exchange);
        }

        // 检查是否是前缀匹配的公共路径
        if (PREFIX_EXCLUDED_PATHS.stream().anyMatch(path::startsWith)) {
            logger.debug("Path {} starts with a public prefix. Bypassing JWT authentication.", path);
            return chain.filter(exchange);
        }

        logger.debug("Path {} requires authentication. Checking Authorization header.", path);

        String authHeader = request.getHeaders().getFirst(HttpHeaders.AUTHORIZATION);

        if (authHeader != null && authHeader.startsWith("Bearer ")) {
            String token = authHeader.substring(7);
            try {
                if (jwtUtil.validateToken(token)) {
                    Long userId = jwtUtil.extractUserId(token);
                    String userRole = jwtUtil.extractUserRole(token);

                    // 将用户ID和角色信息存储到请求属性中，以便后续的控制器或服务访问
                    exchange.getAttributes().put("userId", userId);
                    exchange.getAttributes().put("userRole", userRole);
                    logger.info("Authenticated user: userId={}, role={}", userId, userRole);
                    logger.debug("JwtAuthenticationFilter: Successfully put userId {} and userRole {} into ServerWebExchange attributes for path {}.", userId, userRole, path);

                    // 权限检查：如果访问的是 /api/admin/** 路径，必须是管理员角色
                    if (path.startsWith("/api/admin")) {
                        if (!UserRole.admin.name().equals(userRole)) {
                            logger.warn("User {} with role {} attempted to access admin resource {}", userId, userRole, path);
                            exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN); // 403 Forbidden
                            return exchange.getResponse().setComplete();
                        }
                    }
                    return chain.filter(exchange);
                } else {
                    logger.warn("Invalid JWT token (validation failed): {}", token);
                    exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED); // 401 Unauthorized
                    return exchange.getResponse().setComplete();
                }
            } catch (ExpiredJwtException e) {
                logger.warn("Expired JWT token: {}", e.getMessage());
                exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED); // 401 Unauthorized
                return exchange.getResponse().setComplete();
            } catch (SignatureException e) {
                logger.warn("Invalid JWT signature: {}", e.getMessage());
                exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED); // 401 Unauthorized
                return exchange.getResponse().setComplete();
            } catch (Exception e) {
                logger.error("Error processing JWT token for path {}: {}", path, e.getMessage(), e);
                exchange.getResponse().setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR); // 500 Internal Server Error
                return exchange.getResponse().setComplete();
            }
        } else {
            logger.warn("Missing or malformed Authorization header for protected path: {}", path);
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED); // 401 Unauthorized
            return exchange.getResponse().setComplete();
        }
    }
} 